

import 'dart:convert';
import 'dart:core';
import 'dart:ffi';
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:ble2318ota_plugin_example/util/resolve_util.dart';

class BleSDK {

  static List<int> _generateValue(int size) {
    final List<int> data = List<int>.generate(size, (int index) {
      return 0;
    });
    return data;
  }

  static int _hexByte2Int(int b, int count) {
    return (b & 0xff) * pow(256, count) as int;
  }

  /// 初始化要发送的数据，16个字节，没有设置的位置都默认为0
  /// Initialize the data to be sent, 16 bytes, and default to 0 for positions that are not set
  static List<int> _generateInitValue() {
    return _generateValue(16);
  }

  /// copying array of data
  static void arrayCopy(
      List<int> source, int srcPos, List<int> dest, int destPos, int length) {
    for (int i = 0; i < length; i++) {
      dest[destPos + i] = source[srcPos + i];
    }
  }

  /// message content needed to be sent is converted to List<int>
  static List<int> _getInfoValue(String info, int maxLength) {
    if (info.isEmpty) return [];
    final List<int> nameBytes = utf8.encode(info);
    if (nameBytes.length >= maxLength) {
      /// two commands in total 32 bytes, with only 24 bytes of content.
      /// （32-2*（1cmd+1 Message type + 1 length + 1 validation））
      final List<int> real = List<int>.generate(maxLength, (int index) {
        return 0;
      });
      final List<int> chars = info.codeUnits;
      int length = 0;
      for (int i = 0; i < chars.length; i++) {
        final String s = chars[i].toString();
        final List<int> nameB = utf8.encode(s);
        if (length + nameB.length == maxLength) {
          arrayCopy(nameBytes, 0, real, 0, real.length);
          return real;
        } else if (length + nameB.length > maxLength) {
          /// >24 will result in a byte not being sent to the lower machine causing garbled code
          arrayCopy(nameBytes, 0, real, 0, length);
          return real;
        }
        length += nameB.length;
      }
    }
    return nameBytes;
  }

  /// crc验证
  /// crc validation
  static void _crcValue(List<int> list) {
    int crcValue = 0;
    for (final int value in list) {
      crcValue += value;
    }
    list[15] = crcValue & 0xff;
  }


  static Map DataParsingWithData(List<int> value) {
    switch (value[0]) {
      case 0x47:
        return ResolveUtil.setMethodSucc(_getBcdValue(value[0]).toString());
    }
    return ResolveUtil.setMethodError(_getBcdValue(value[0]).toString());
  }


  ///进入dfu模式
  ///Entering dfu mode
  static Uint8List enterOTA() {
    final List<int> value = _generateInitValue();
    value[0] = 0x47;
    _crcValue(value);
    return Uint8List.fromList(value);
  }


  /// 十进制转bcd码（23 -> 0x23）
  /// Decimal to bcd code (23 ->0x23)
  static int _getBcdValue(int value) {
    String data = value.toString();
    if (data.length > 2) data = data.substring(2);
    return int.parse(data, radix: 16);
  }

  ///检查是否需要升级
  static Uint8List checkUpdateFile(Uint8List binByte,Uint8List binMd5,int fileNumber,bool languageUp){
    return _checkFile(binByte, binMd5, 1, fileNumber);
  }

  static Uint8List checkEndFile(Uint8List binByte,Uint8List binMd5,int fileNumber){
    return _checkFile(binByte, binMd5, 2, fileNumber);
  }


  static Uint8List _checkFile(Uint8List binByte,Uint8List binMd5,int mode,int fileName){
    int length = binByte.length;
    int crc16 = _calcCrc16(binByte,binByte.length);
    Uint8List value = Uint8List(27);
    value[0] = 0x92;
    value[1] = mode;
    value[2] = fileName;
    value[3] = (length & 0xff);
    value[4] = ((length >> 8) & 0xff);
    value[5] = ((length >> 16) & 0xff);
    value[6] = ((length >> 24) & 0xff);
    value[7] = (crc16 & 0xff);
    value[8] = ((crc16 >> 8) & 0xff);
    arrayCopy(binMd5, 0, value, 9, binMd5.length);
    int crcValue16 = _calcCrc16(value, 25);
    value[25] = (crcValue16 & 0xff);
    value[26] = ((crcValue16 >> 8) & 0xff);
    return value;
  }

  static int _calcCrc16(Uint8List pArray,int length){
    int wCRC = 0xFFFF;
    int CRC_Count = length;
    // int i;
    int num = 0;
    while(CRC_Count > 0){
      CRC_Count--;
      wCRC = wCRC ^ (0xFF & pArray[num++]);
      for(int i = 0; i < 8; i++){
        if((wCRC & 0x0001) == 1){
          wCRC - wCRC >> 1 ^ 0xA001;
        }else{
          wCRC = wCRC >> 1;
        }
      }
    }
    return wCRC;
  }
}
